import { EventsRes, SceneGraph } from '@amcax/base';
import { ctx2 } from '@app-cad/module';
import { wsApi } from '@app-cad/server';
import { Vector2tuple, Vector3 } from 'three-legacy';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '../../../events/SketchEventCenter';
import CmdBase, { PickType } from '../../CmdBase';
import { MouseState, State } from './types';
import {
  calculatePoint,
  getLineIntersectionTwo,
  isEffectiveValue,
  isEquals,
} from '@app-cad/common/utils';

export default class CmdInteractorTwo extends CmdBase {
  startPoint: Vector3; // 绘制起点
  secPoint: Vector3; // 绘制第二点
  endPoint: Vector3; // 绘制第三点
  currentState: MouseState = State.NONE;
  private threePoint: (Vector2tuple | string)[] = new Array(3);

  constructor() {
    super();
    this.registerEvents();
  }

  reset() {
    this.currentState = State.NONE;
    this.startPoint = null;
    this.secPoint = null;
    this.endPoint = null;
    this.threePoint = [];
    this.clearLine();
    this.removeTempPoint();
  }

  registerEvents() {
    sketchEventCenter()
      .setState('SketchCircle')
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .on(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy.bind(this));
  }

  unregisterEvents() {
    sketchEventCenter()
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .off(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .setDefault();
  }

  releaseObjects() {
    this.clearLine();
    this.assisGroup.clear();
    SceneGraph.emptyGroup(this.assisGroup);
    ctx2.viewer.requestRender();
  }

  onMouseMove = (e: EventsRes) => {
    this.setMouseWV(e, true);
    if (this.currentState === State.NONE) {
      return;
    }
    if (this.currentState === State.DRAW) {
      this.secPoint = this.mouseWV.clone();
    } else if (this.currentState === State.NEXT_DRAW) {
      this.endPoint = this.mouseWV.clone();
    }
    this.createAssistPoint(this.mouseWV.clone(), true);
    this.preview();
  };

  // 判断点是否重复
  isRepeatPoint = (point: Vector2tuple | string) => {
    return this.threePoint.some((item) => {
      if (typeof item === 'string') {
        return item === point;
      }
      return isEquals(item, point);
    });
  };

  onMouseDown = (e: EventsRes) => {
    if (e.button.onLeft && this.currentState !== State.FINISH) {
      const point: Vector2tuple | string =
        this.pickType === PickType.Point
          ? this.pickSnapInfo.id
          : [this.mouseWV.x, this.mouseWV.y];
      if (this.isRepeatPoint(point)) {
        return;
      }
      this.threePoint[this.currentState] = point;
      const flag = this.currentState === State.DRAW;
      // 鼠标左键，进行绘制
      if (this.currentState === State.NONE) {
        this.startPoint = this.mouseWV.clone();
        this.previewLines.line = null;
        this.currentState = State.DRAW;
      } else if (this.currentState === State.DRAW) {
        this.secPoint = this.mouseWV.clone();
        this.currentState = State.NEXT_DRAW;
      } else if (this.currentState === State.NEXT_DRAW) {
        this.endPoint = this.mouseWV.clone();
        this.currentState = State.FINISH;
        this.finishDraw();
      }
      this.createAssistPoint(this.mouseWV.clone(), null, null, flag);
    } else if (e.button.onRight && !this.closeRightClick) {
      this.currentState = State.NONE;
      // 鼠标右键，取消绘制
      this.destroy();
    }
  };

  preview() {
    if (
      this.currentState === State.NONE ||
      this.currentState === State.FINISH
    ) {
      return;
    }
    const circleInfo = this.getCircleInfo();
    if (
      circleInfo &&
      isEffectiveValue(circleInfo.center) &&
      isEffectiveValue(circleInfo.radius)
    ) {
      this.createAssistPoint(circleInfo.center, true, 1);
      // // 绘制圆
      const params = this.getArcVertexs({
        x: circleInfo.center.x,
        y: circleInfo.center.y,
        radius: circleInfo.radius,
        startAngle: 0,
        endAngle: Math.PI * 2,
        clockWise: true,
      });
      this.createUpdateLine(params);
      ctx2.viewer.requestRender();
    }
  }

  getCircleInfo() {
    if (this.currentState === State.DRAW) {
      const center = new Vector3()
        .addVectors(this.startPoint, this.secPoint)
        .divideScalar(2);
      const radius = center.distanceTo(this.startPoint);
      return {
        center,
        radius,
      };
    } else if (this.currentState === State.NEXT_DRAW) {
      const center1 = new Vector3()
        .addVectors(this.startPoint, this.secPoint)
        .divideScalar(2);
      const center2 = new Vector3()
        .addVectors(this.secPoint, this.endPoint)
        .divideScalar(2);
      const vec1 = new Vector3()
        .subVectors(this.startPoint, this.secPoint)
        .normalize();
      const vec2 = new Vector3()
        .subVectors(this.secPoint, this.endPoint)
        .normalize();
      if (isEquals(vec1, vec2)) {
        return {
          center: center1,
          radius: center1.distanceTo(this.startPoint),
        };
      }
      const v1 = new Vector3(vec1.y, -vec1.x, 0);
      const v2 = new Vector3(vec2.y, -vec2.x, 0);
      const p1 = calculatePoint(v1, 1, center1);
      const p2 = calculatePoint(v2, 1, center2);
      const center3 = getLineIntersectionTwo(center1, p1, center2, p2);
      if (isNaN(center3.x) || isNaN(center3.y) || !center3.x || !center3.y) {
        return {
          center: center1,
          radius: center1.distanceTo(this.startPoint),
        };
      }
      const center = new Vector3(center3.x, center3.y, 0);
      return {
        center,
        radius: center.distanceTo(this.startPoint),
      };
    }
    return null;
  }

  async finishDraw() {
    try {
      const res = await wsApi.createSketchCircle3P(this.sketchId, {
        mode: 'three-point',
        points: this.threePoint,
        curveStyle: this.lineType,
      });
      await this.render({ added: res.added });
    } catch (error) {
      //
    }
    this.reset();
    this.releaseObjects();
  }
}
